package com.indexingsystem.db.mongoDB;

import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.log4j.PropertyConfigurator;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.indexingsystem.boss.logback.LogCvt;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoCredential;
import com.mongodb.ReadPreference;
import com.mongodb.ServerAddress;
import com.mongodb.WriteConcern;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.UpdateOptions;

/**
 * mongo 操作接口
 * 
 * @ClassName: MongoService
 * 
 */
public abstract class MongoService {

	private static Logger			logger				= LoggerFactory.getLogger( MongoService.class );
	/**
	 * 写操作
	 */
	protected static MongoClient	writeMongoClient	= null;
	protected static MongoDatabase	writeMongoDB		= null;

	/**
	 * 读操作
	 */
	protected static MongoClient	readMongoClient		= null;
	protected static MongoDatabase	readMongoDB			= null;

	/**
	 * 分页临界值
	 */
	protected static Long			minRedisPageCount	= 0l;

	// 初始化Mongo连接池
	static {
		FileReader fr = null;
		/*try {
			Properties props = new Properties();
			props.load( LogCvt.class.getClassLoader().getResourceAsStream( "mongo.properties" ) );
			PropertyConfigurator.configure( props );

			MongoClientOptions.Builder build = new MongoClientOptions.Builder();
			build.connectionsPerHost( Integer.valueOf( props.getProperty( "mongo.pool.connectionsPerHost" ) ) );
			build.threadsAllowedToBlockForConnectionMultiplier( Integer.valueOf( props
					.getProperty( "mongo.pool.threadsAllowedToBlockForConnectionMultiplier" ) ) );
			build.maxWaitTime( Integer.valueOf( props.getProperty( "mongo.pool.maxWaitTime" ) ) );
			build.connectTimeout( Integer.valueOf( props.getProperty( "mongo.pool.connectTimeout" ) ) );
			MongoClientOptions myOptions = build.build();

			// boolean isAuth = false;
			String databaseName = props.getProperty( "mongo.read.databaseName" );
			// 写数据库连接实例
			String writeUserName = props.getProperty( "mongo.write.userName" );
			String writePwd = props.getProperty( "mongo.write.password" );
			MongoCredential credentialWrite = MongoCredential.createCredential( writeUserName, databaseName, writePwd.toCharArray() );
			if (writeUserName == null || "".equals( writeUserName.trim() ) || writePwd == null || "".equals( writePwd.trim() )) {
				writeMongoClient = new MongoClient( new ServerAddress( props.getProperty( "mongo.write.host" ), Integer.valueOf( props
						.getProperty( "mongo.write.port" ) ) ), myOptions );
			} else {
				writeMongoClient = new MongoClient( new ServerAddress( props.getProperty( "mongo.write.host" ), Integer.valueOf( props
						.getProperty( "mongo.write.port" ) ) ), Arrays.asList( credentialWrite ), myOptions );
				// isAuth = true;
			}
			writeMongoDB = writeMongoClient.getDatabase( props.getProperty( "mongo.write.databaseName" ) );
			
			final String WRITE_WRITECONCERNY = "mongo.write.writeConcern";
			String writeConcern = props.getProperty( WRITE_WRITECONCERNY );
			String defWCMsgStr = " writeConcern将使用默认的:" + writeMongoDB.getWriteConcern().toString();
			if (writeConcern != null && !(writeConcern = writeConcern.trim()).equals( "" )) {
				WriteConcern wc = WriteConcern.valueOf( writeConcern );
				if (null != wc) {
					writeMongoDB.withWriteConcern( wc );
				} else {
					logger.warn( "配置" + WRITE_WRITECONCERNY + "有误, WriteConcern类找不到" + writeConcern + "属性!" + defWCMsgStr );
				}
			} else {
				logger.warn( "未配置" + WRITE_WRITECONCERNY + "!" + defWCMsgStr );
			}

			// 读数据库连接实例
			// isAuth = false;
			String readUserName = props.getProperty( "mongo.read.userName" );
			String readPwd = props.getProperty( "mongo.read.password" );
			MongoCredential credentialRead = MongoCredential.createCredential( readUserName, databaseName, readPwd.toCharArray() );
			if (writeUserName == null || "".equals( writeUserName.trim() ) || writePwd == null || "".equals( writePwd.trim() )) {
				readMongoClient = new MongoClient( new ServerAddress( props.getProperty( "mongo.read.host" ), Integer.valueOf( props
						.getProperty( "mongo.read.port" ) ) ), myOptions );
			} else {
				readMongoClient = new MongoClient( new ServerAddress( props.getProperty( "mongo.read.host" ), Integer.valueOf( props
						.getProperty( "mongo.read.port" ) ) ), Arrays.asList( credentialRead ), myOptions );
				// isAuth = true;
			}
			readMongoDB = readMongoClient.getDatabase( props.getProperty( "mongo.read.databaseName" ) );
			// if (isAuth) {
			// // readMongoDB.authenticate( readUserName, readPwd.toCharArray()
			// );
			// readMongoDB.addUser( readUserName, readPwd.toCharArray() );
			// }
			// readMongoDB.setReadPreference(
			// ReadPreference.secondaryPreferred() );
			readMongoClient.setReadPreference( ReadPreference.secondaryPreferred() );

			minRedisPageCount = Long.valueOf( props.getProperty( "mongo.redisPageCount.min" ) );
		} catch (IOException e) {
			logger.error( e.getMessage(), e );
		} finally {
			try {
				if (fr != null) {
					fr.close();
				}
			} catch (IOException e) {
			}
		}*/
	}

	/**
	 * 
	 * @Description:获取集合（表）
	 * @param connName
	 * @return DBCollection
	 * 
	 */
	public MongoCollection<Document> getReadDBCollection(String connName) {
		return readMongoDB.getCollection( connName );
	}

	/**
	 * 
	 * @Description:获取集合（表）
	 * @param connName
	 * @return DBCollection
	 * 
	 */
	public MongoCollection<Document> getWriteDBCollection(String connName) {
		return writeMongoDB.getCollection( connName );
	}

	/**
	 * 关闭
	 * 
	 */
	public static void closeConnection() {
		// if (mongoClient != null) {
		// mongoClient.close();
		// }
	}

	/**
	 * @return the writeMongoDB
	 */
	public static MongoDatabase getWriteMongoDB() {
		return writeMongoDB;
	}

	/**
	 * @param writeMongoDB
	 *            the writeMongoDB to set
	 */
	public static void setWriteMongoDB(MongoDatabase writeMongoDB) {
		MongoService.writeMongoDB = writeMongoDB;
	}

	/**
	 * @return the readMongoDB
	 */
	public static MongoDatabase getReadMongoDB() {
		return readMongoDB;
	}

	/**
	 * @param readMongoDB
	 *            the readMongoDB to set
	 */
	public static void setReadMongoDB(MongoDatabase readMongoDB) {
		MongoService.readMongoDB = readMongoDB;
	}

	/**
	 * 
	 * @param obj
	 *            增加的对象
	 * @param connName
	 *            表连接名称
	 * @return 影响结果 int
	 * 
	 */
	public abstract void add(Document document, String connName);

	/**
	 * 
	 * add:批量添加
	 * 
	 * @param dbObjects
	 * @param connName
	 * @return
	 * 
	 */
	public abstract void addList(List<Document> list, String connName);

	/**
	 * 
	 * add:批量添加
	 * 
	 * @param dbObjects
	 * @param connName
	 * @return
	 * 
	 */
	public abstract void addArray(Document[] dbObjects, String connName);

	/**
	 * 新增单条数据。
	 * 
	 * @param bean
	 */
	public abstract <T> void insertOne(Object bean, String connName);

	/**
	 * 删除数据.
	 * 
	 * @param condition
	 * @param connName
	 */
	public abstract void delete(Map<String, Object> condition, String connName);

	/**
	 * 获取全部数据.
	 * 
	 * @param clazz
	 * @param connName
	 * @return
	 */
	public abstract List<Document> findAll(Class clazz, String connName);

	/**
	 * 查询集合所有记录.
	 * 
	 * @param collName
	 * @return
	 */
	public abstract List<Document> findAll(String collName);

	/**
	 * 查询指定数据
	 */
	public abstract <T> List<T> findCondition(Map<String, Object> condition, Class clazz, String connName);

	/**
	 * 单页分页查询.
	 * 
	 * @param db
	 * @param tableName
	 * @param bson
	 * @param skip
	 * @param limit
	 * @return
	 */
	public abstract List<Document> queryPages(String connName, Bson bson, Document pxObj, Document fetchFields, int pageNo, int pageSize);

	/**
	 * 多页分页查询.
	 * 
	 * @param db
	 * @param tableName
	 * @param bson
	 * @param pageSize
	 * @return
	 */
	public abstract List<Document> queryPages(String connName, Bson bson, Document pxObj, Document fetchFields, int pageSize);

	/**
	 * 带条件聚合查询.
	 * 
	 * @param aggregateList
	 * @param connName
	 * @return
	 */
	public abstract List<Document> queryAggregateList(Bson aggregateList, Class clazz, String connName);

	/**
	 * 删除所有集合.
	 * 
	 * @param connName
	 */
	public abstract void deleteAll(String connName);

	/**
	 * 删除单个集合.
	 * 
	 * @param connName
	 * @param document
	 */
	public abstract void deleteOne(String connName, Document document);

	/**
	 * 单个修改集合:带查询条件修改.
	 * 
	 * @param filter
	 * @param updateDoc
	 * @param connName
	 */
	public abstract void updateOne(Bson filter, Bson updateDoc, String connName);

	/**
	 * 单个修改集合：带查询条件修改，带UpdateOptions 条件.
	 * 
	 * @param filter
	 * @param updateDoc
	 * @param options
	 * @param connName
	 */
	public abstract void updateOne(Bson filter, Bson updateDoc, UpdateOptions options, String connName);

	/**
	 * 删除指定的所有数据
	 * 
	 * @param bson
	 * @param collName
	 */
	public abstract void deleteAll(Bson bson, String collName);

	/**
	 * 删除指定的一条数据
	 * 
	 * @param b
	 * @param collName
	 */
	public abstract void deleteOne(Bson bson, String collName);

	/**
	 * 按查询条件批量修改
	 * 
	 * @param b
	 * @param doc
	 * @param collName
	 */
	public abstract void updateAll(Bson bson, Document doc, String collName);

	/**
	 * 替换更新整个document。
	 * 
	 * @param bson
	 * @param newDocument
	 * @param options
	 */
	public abstract void replaceOne(Bson bson, Document newDocument, UpdateOptions options, String collName);

	/**
	 * 获取文档查询条件的总数量.
	 * 
	 * @param aggregateList
	 * @param connName
	 * @return
	 */
	public abstract Integer queryAggregateListMaxCount(Bson aggregateList, String connName);
}